﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using ShevaEngine.Core.Interfaces;
using Microsoft.Xna.Framework;

namespace ShevaEngine.Core.Modules.Materials
{
    /// <summary>
    /// Spravce textur.
    /// </summary>
    public class TextureManager : IUpdateAble
    {
        /// <summary>Singleton.</summary>
        public static readonly TextureManager Instance = new TextureManager();

        /// <summary>Texture configurations.</summary>
        private SortedDictionary<string, Texture> Textures;
        /// <summary>Texture states.</summary>
        private List<TextureState> TextureStates;
        /// <summary>Texture search.</summary>
        private SortedDictionary<Textures, UInt16> TextureSearch;
        /// <summary>White texture.</summary>
        public Texture2D WhiteTexture { get; private set; }
        /// <summary>Animated texture 2D configurations.</summary>
        public Dictionary<string, AnimatedTexture2DConfiguration> AnimatedTexture2DConfigurations;
        /// <summary>Animated textures.</summary>
        public List<AnimatedTexture2D> AnimatedTextures;
        /// <summary>Counter.</summary>
        private int counter;

        /// <summary>
        /// Vraci pozadovaneou texturu.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TextureState this[UInt16 key]
        {
            get
            {
                return this.TextureStates[key];
            }
        }

        /// <summary>
        /// Konstruktor.
        /// </summary>
        /// <param name="engine"></param>
        private TextureManager()
        {
            this.Textures = new SortedDictionary<string, Texture>();
            this.TextureStates = new List<TextureState>();
            this.TextureSearch = new SortedDictionary<Textures, ushort>(new TexturesComparer());
            this.AnimatedTextures = new List<AnimatedTexture2D>();

            try
            {
                this.AnimatedTexture2DConfigurations =
                    ShevaEngine.Instance.Content.Load<Dictionary<string, AnimatedTexture2DConfiguration>>("Textures\\AnimatedTextures");
            }
            catch
            {
                this.AnimatedTexture2DConfigurations = new Dictionary<string, AnimatedTexture2DConfiguration>();
            }

            this.WhiteTexture = this.GetTexture("White") as Texture2D;            
        }


        /// <summary>
        /// Vraci pozadovaneou texturu.
        /// </summary>
        /// <param name="textureName"></param>
        /// <returns></returns>
        public Texture GetTexture(string textureName)
        {
            if (!this.Textures.ContainsKey(textureName))
            {
                try
                {
                    if (this.AnimatedTexture2DConfigurations.ContainsKey(textureName))
                    {
                        AnimatedTexture2D newAnimatedTexture =  new AnimatedTexture2D(this.AnimatedTexture2DConfigurations[textureName]);

                        this.AnimatedTextures.Add(newAnimatedTexture);

                        return newAnimatedTexture;
                    }
                    else
                        this.Textures.Add(textureName, ShevaEngine.Instance.Content.Load<Texture2D>("Textures\\" + textureName));                    
                }
                catch
                {
                    ShevaLog.Instance.AddInfoLine("WARNING : Texture " + textureName + " not found !");

                    return new Texture2D(ShevaEngine.Instance.GraphicsDevice, 16, 16, false, SurfaceFormat.Color);
                }
            }

            return this.Textures[textureName];
        }

        /// <summary>
        /// Metoda vypise seznam nactenych textur.
        /// </summary>
        public void DumpTextures()
        {
            ShevaLog.Instance.AddInfoLine("DUMPING TEXTURE MANAGER");

            foreach (KeyValuePair<string, Texture> item in this.Textures)
                ShevaLog.Instance.AddInfoLine(item.Key + " : " + item.Value.Format.ToString());
        }               

        /// <summary>
        /// Method returns textureState id.
        /// </summary>
        /// <returns></returns>
        public UInt16 GetTextureStateId(Textures textures)
        {
            if (!this.TextureSearch.ContainsKey(textures))
            {
                this.TextureSearch.Add(textures, (UInt16)this.TextureStates.Count);

                TextureState newTextureState = new TextureState();

                foreach (KeyValuePair<string, string> item in textures)
                    newTextureState.Add(item.Key, this.GetTexture(item.Value));

                this.TextureStates.Add(newTextureState);
            }

            return this.TextureSearch[textures];
        }

        /// <summary>
        /// Method Update.
        /// </summary>
        /// <param name="time"></param>
        public void Update(GameTime time)
        {
            for (counter = this.AnimatedTextures.Count - 1; counter >= 0; counter--)
                this.AnimatedTextures[counter].Update(time);
        }
    }
}
